﻿#region Using's

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;

using MyUtils;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Test.MyUtils.TestHelp;

#endregion

namespace Test.MyUtils
{
	[TestClass]
	public class Reflection : FixtureMsTest
	{
		class ctest
		{
			int customProperty;
			int field = 222;

			public ctest()
			{
				testPro = "555";
			}

			public object AsObject
			{
				get { return this; }
			}

			public string testPro { get; set; }

			public int Field_
			{
				get { return field; }
			}

			public int this[int a, int b]
			{
				get { return a * b; }
				set { field = value + this[a, b]; }
			}

			public int this[int a]
			{
				get { return 1; }
			}

			public int this[float b]
			{
				get { return 2; }
			}

			public int CustomProperty
			{
				get { return customProperty; }
				set { customProperty = value; }
			}

			public string MyMethod()
			{
				return "test1 string";
			}

			public string MyMethod0(int value)
			{
				return value.ToString();
			}

			public string MyMethod(int value)
			{
				return value.ToString();
			}

			public string MyMethod2(object value)
			{
				return "test1 string 2";
			}

			public string MyMethod3(IEnumerable value)
			{
				return "test1 string 3";
			}
		}

		readonly ctest test = new ctest();


		int ambig(int i)
		{
			return i + 1;
		}

		int ambig(float i)
		{
			return (int)i + 2;
		}

		int ambig(double i)
		{
			return (int)i + 3;
		}

		[TestMethod]
		public void Should_allow_to_return_method_property_and_field_results()
		{
			Assert.AreEqual("test1 string", new ctest().AsObject.Reflect("MyMethod"));
			Assert.AreEqual("555", new ctest().AsObject.Reflect("tEsTpro"));
			Assert.AreEqual(222, new ctest().AsObject.Reflect("field"));
		}

		[TestMethod]
		public void Should_allow_works_with_custom_property()
		{
			Assert.AreEqual(0, test.Reflect("CustomProperty"));
			test.Reflect("CustomProperty", 5);
			Assert.AreEqual(5, test.Reflect("CustomProperty"));
		}

		[TestMethod]
		public void Should_get_indexers()
		{
			Equal(4, test.Reflect("value", 2, 2));
			Equal(20, test.Reflect("value", 4, 5));
		}

		[TestMethod]
		public void Should_reflect_parametrized_methods()
		{
			Equal(-1, 5.Reflect("CompareTo", 6));
			Equal(255, typeof(int).Reflect("Parse", "ff", NumberStyles.HexNumber));
		}

		[TestMethod]
		public void Should_reflect_setters()
		{
			var test = new ctest();
			test.Reflect("field", 333);
			Assert.AreEqual(333, test.Field_);
			test.Reflect("testpro", "777");
			Assert.AreEqual("777", test.testPro);
		}

		[TestMethod]
		public void Should_reflect_with_deep_obj_path()
		{
			Equal("Int32", 5.Reflect("gettypecode.tostring"));
			False((bool)5.Reflect("tostrinG.endsWiTh", "g"));
			True((bool)56.Reflect("tostrinG.endsWiTh", "6"));
		}

		[TestMethod]
		public void Should_resolve_ambigous_reference()
		{
			Equal(2, this.Reflect("ambig", 1));
			Equal(3, this.Reflect("ambig", 1f));
			Equal(4, this.Reflect("ambig", 1d));
			Equal(1, test.Reflect("value", 5));
			Equal(2, test.Reflect("value", 5f));
		}

		[TestMethod]
		public void Should_set_indexers()
		{
			test.Reflect("value", 2, 2, 3);
			Equal(7, test.Reflect("field"));
			test.Reflect("value", 4, 5, 8);
			Equal(28, test.Reflect("field"));
		}

		class Gen<T, F>
		{
			public T Peter;
			public List<F> Col = new List<F>();
			public R Some<R>(T val)
			{
				return (R)(object)val;
			}
			public object Some2(T val)
			{
				return val;
			}
		}

		class InnerGen
		{
			public List<int> list = new List<int>();
		}

		[TestMethod]
		public void Should_works_with_generic_classes()
		{
			var myc = new Gen<int, int>();
			myc.Reflect("col.add", 5);
			Assert.AreEqual(1, myc.Reflect("col.count"));
		}

		[TestMethod]
		public void Should_works_with_generic_methods()
		{
			var myc = new Gen<int, int>();
			Assert.AreEqual(5, myc.Reflect("some", typeof (int), 5));
		}

		[TestMethod]
		public void Should_works_with_generic_types()
		{
			var myc = new Gen<int, int>();
			Assert.AreEqual(5, myc.Reflect("some2", 5));
		}

		[TestMethod]
		public void Should_work_withaggregated_genericlist()
		{
			var clazz = new InnerGen();
			clazz.Reflect("list.add", 5);
			Assert.AreEqual(1, clazz.Reflect("list.count"));
		}

		[TestMethod]
		public void Should_allow_pass_inherited_class_to_method_parameter()
		{
			Assert.AreEqual("3", test.Reflect("mymethod", 3));
			Assert.AreEqual("test1 string 2", test.Reflect("mymethod2", new object()));
			Assert.AreEqual("test1 string 2", test.Reflect("mymethod2", 5.5));
			Assert.AreEqual("test1 string 3", test.Reflect("mymethod3", "q"));
		}

		[TestMethod]
		public void Should_allow_pass_null_to_method_parameter()
		{
			Assert.AreEqual("test1 string 2", test.Reflect("mymethod2", null));
			Assert.AreEqual("test1 string 3", test.Reflect("mymethod3", null));
		}

		[TestMethod]
		public void Should_not_allow_pass_null_to_value_method_parameter()
		{
			Assert.AreEqual("0", test.Reflect("mymethod", null));
		}

		[TestMethod]
		public void Should_allow_pass_null_as_default_to_value_method_parameter2()
		{
			Assert.AreEqual("0", test.Reflect("mymethod0", null));
		}
	}
}